<?php


namespace app\controller;


use app\BaseController;
use app\model\User;
use think\facade\Db;

class  DataTest extends BaseController
{
    //数据库事件方法为 Db::event('事件名','执行函数')
    //before_select              select查询前回调
    //before_find                find 查询前回调
    //after_insert               insert操作成功后回调
    //after_update                update操作成功后回调
    //after_delete               delete操作成功后回调
    public function initialize()
    {
       // parent::initialize(); // TODO: Change the autogenerated stub
        Db::event('before_select',function($query){
            echo '执行了批量查询';
        });
    }

    //控制器查询
   public function index(){
       //控制器获取
//       $user = Db::connect('mysql')->table('tp_user')->select();
//       return json($user);


       //一 单数据查询
       // find 没有查询到 返回null
       //findOrFail() 没有查询到 抛出异常
       //findOrEmpty() 没有查询到 返回一个空数值
//       $user = Db::table('tp_user')->where('id',27)->find();
//       return json($user);

       //Db::getLastSql() 获得最近一条SQL查询语句
//       return Db::getLastSql();


       //二 数据集查询
       //select() 没有数据返回空数组
       //selectOrFail()  没有数据抛出异常
//       $users = Db::table('tp_user')->select();
//       dump($users);
//       $users = Db::table('tp_user')->select()->toArray();
//       dump($users);



       //当再数据库配置文件中设置了前缀，那么我们可以使用name()方法忽略前缀
       //return Db::name('user')->select();

       //三 其他查询
       //value()  查询某个字段的值 ，没有返回null
       //return Db::name('user')->where('id',270)->value('username');
       //colunm()  可查询指定列的值(多个) 没有数据返回空数组
       //dump(Db::name('user')->column('username'));
       //dump(Db::name('user')->column('username','id')); //设置id为索引


       //为避免数据过多，内存消耗过大 可以使用 chunk() 方法分批处理数据
//       Db::name("user")->chunk(3,function($users){
//           foreach ($users as $user){
//               dump($user);
//           }
//           echo 1;
//       });

       //对于海量数据的内存开销  利用PHP生成器特性  PHP生成器 了解一下 一次制度一行，然后自动定位到下一行读取
//       $cursor = Db::name('user')->cursor();
//       foreach ($cursor as $user){
//           dump($user);
//       }


       //使用removeOption() 可以清理掉上一次查询保留的值
       //$userQuery->removeOption('where')->select();
   }

   //模型查询
   public function getUser(){
       //模型获取
       $user = User::select();
       return json($user);
   }

   //数据插入
    public function insert(){
       $data = [
           'username' => '杀生丸',
           'password' => '123',
           'gender'  => '男',
           'email' => '123456789@123.com',
           'price' => '12800',
           'details' =>'123'

       ];
       //插入成功 返回1
        //如果添加一个不存在的字段数据 抛出异常 使用 strick(false) 忽略异常
//       return Db::name('user')->strick(false)->insert($data);

        //如果采用的是mysql数据库 支持replace写入
        //insert 表中存在主键想用则报错
        //replace 表中主键相同则修改更新
//        Db::name('user')->replace()->insert($data);
//        return Db::getLastSql();

        //用insertGetId() 可以在新增成功后返回当前数据ID
        //return Db::name('user')->insertGetId($data);



        //save() 新增方法
        //save() 是一个通用方法 可以自行判断是新增还是修改（更新）数据
        //判断依据  数据是否存在主键 存在修改  不存在新增
        //Db::name('user')->save($data);

    }

     //批量数据新增
    public function insertAll(){
       //insertAll()
        $data = [
           [ 'username' => '杀生丸',
            'password' => '123',
            'gender'  => '男',
            'email' => '123456789@123.com',
            'price' => '12800',
            'details' =>'123'
          ],
           [
               'username' => '杀生丸',
               'password' => '123',
               'gender'  => '男',
               'email' => '123456789@123.com',
               'price' => '12800',
               'details' =>'123'
           ]
        ];
        return Db::name('user')->insertAll($data);
       //也支持replace方法
       // return Db::name('user')->replace()->insertAll($data);
   }

   //更新数据
    public function update(){
       $data = [
           'username' =>"犬夜叉"
       ];
       //如果修改是数据本身包含主键  那么可以忽略掉where 条件
//         return Db::name('user')->where('id',303)->update($data);

        //如果想要一些字段修改师执行SQL函数操作 可以使用exp() 方法
//        Db::name('user')->where('id',302)->exp('email','UPPER(email)')->update();
//        return Db::getLastSql();

        //使用 inc() dec()
//        Db::name('user')->where('id',303)->inc('price')->dec('status',2)->update();

        //使用 raw() 简单粗暴的方法
//        Db::name('user')->where('id',304)->update(
//            [
//                'email'=>Db::raw('UPPER(email)'),
//                'price'=>Db::raw('price+2'),
//                'status'=>Db::raw('status-1')
//            ]
//        );

        //使用save() 方法 必必须使用主键
   }

   //删除数据
    public function delete(){
       //根据主键 极简单删除
//        Db::name('user')->delete(1);
//        Db::name('user')->delete([2,3,4]);
//
//        //正常情况下 还是使用where 来删除
//        Db::name('user')->where('id',100)->delete();

    }

    //数据查询
    public function query(){

        //比较查询
        //where('字段名','查询表达式','查询条件')
//        $user = Db::name('user')->where('id','=','76')->find();
//        return json($user);

        //区间查询
        //使用 like 表达式 进行模糊查询
//        Db::name('user')->where('email','like','xiao%')->select();
       //like表达式还可以支持数组传递进行模糊查询
//        Db::name('user')->where('email','like',['xiao%','%ghj'])->select();
        //like表达式具有两个快捷方式  whereLike() whereNotLike()
//        Db::name('user')->whereNotLike('email',['xiao%','%ghj'])->select();
        //between表达式具有两个快捷方式 whereBetween() whereNotBetween()
//        Db::name('user')->whereNotBetween('id','19,25')->select();
        //in 表达式具有两个快捷键 whereIn() whereNotIn()
//        Db::name('user')->whereIn('id',[19,25])->select();
        //null 表达式 具有连个快捷方式 whereNull() whereNotNull()
//        Db::name('user')->where('id','null')->select();
//        Db::name('user')->whereNotNull('uid')->select();
//        return Db::getLastSql();

        //EXP查询
        //使用 exp 可以自定义字段后 的SQL语句
        Db::name('user')->where('id','exp','IN(12,34,57)')->select();
        return Db::getLastSql();
    }

    //数据库时间查询
    public function time(){
       //传统方式
//       Db::name('user')->where('create_time','>','2018-1-1')->select();
//       Db::name('user')->where('create_time','not between',['2018-1-1','2019-1-1'])->select();

        //快捷方式
        //whereTime  > < >= <=
//        Db::name('user')->whereTime('create_time','>=','2018-1-1')->select();

        //whereBetweenTime() whereNotBetweenTime()
//        Db::name('user')->whereNotBetweenTime('create_time','2018-1-1','2010-1-1')->select();



        //固定查询
        //1 使用 whereYear 查询今年的数据，去年是大户局 和某一年的数据
//        Db::name('user')->whereYear('create_time','this year')->select();
//        Db::name('user')->whereYear('create_time','last year')->select();
//        Db::name('user')->whereYear('create_time','2000')->select();
        //whereMonth  whereDay 也是一样



        //其他查询
        //查询指定时间的数据 比如两个小时内
//        Db::name('user')->whereTime('create_time','-2 hours')->select();
        //查询两个时间字段时间有效期的数据，比如会员开始到结束时间
//        Db::name('user')->whereBetweenTimeField('create_time','update_time')->select();
//        return Db::getLastSql();
    }

    //聚合 原生 子查询
    public function poly(){
        $handle = Db::name('user');
        //聚合查询
       //使用count() 方法 可以求出所查询数据的数量  count() 可指定字段
//        Db::name('user')->count('uid');

        //使用 max() 方法 求出所查询数据字段的最大值  min()求最小值
        //如果使用 max() min() 方法，求出的值不是数值，则可以使用第二参数强制转换  max('email',false)
//        $handle->max('price');

        //使用 avg() 求出所查询数据字段的平均值
//        $handle->avg('price');

        //使用 sum() 求出所查询数据字段的总和
//        $handle->sum('price');



        //子查询
        //使用 fetchSql() 方法 ，可以设置不执行SQL 而返回SQL语句 ，默认 true
//        return $handle->fetchSql()->select();
        //使用 buildSql() 方法 也返回SQL语句 不需要执行select() 且有括号
//        return $handle->buildSql();

        //结合 以上两个方法 我们实现一个子查询
//        $subQuery = Db::name('two')->field('uid')->where('gender','男')->buildSql(true);
//        $result = Db::name('one')->where('id','exp','IN '.$subQuery)->select();
//        return json($result);

//        $result = Db::name('one')->where('id','in',function($query){
//            $query->name('two')->field('uid')->where('gender','男');
//        })->select();
//        return Db::getLastSql();
//        return json($result);


        //原生查询
        //1 使用 query() 进行原生SQL查询，适用于读取操作  SQL错误返回false
        //2 使用 execute() 进行原生SQL更新写入等，SQL错误返回false
   }

   //链式查询 上 where()  field()  alias()
    public function linkup(){
        //where()
        //1表达式查询，就是where() 方法的基础查询方式
        //2关联数组查询 通过键值对匹配的查询方式
//        $user = Db::name('user')->where(
//            ['gender'=>'男',
//             'price'=>100       // 'price'=>[60,70,80]
//            ]
//        )->select();
        //3索引数组查询 ，通过数组里的数组拼接方式来查询
//        $user = Db::name('user')->where([
//            ['gender','=','男'],
//            ['price','=','100']
//        ])->select();

        //4字符串形式传递，简单粗暴的查询方式，whereRaw() 支持复杂字符串格式
//        $user = Db::name('user')->whereRaw('gender="男" AND price IN (60,70,80)')->select();
        //5 如果SQL查询采用了预处理模式。比如 id=:id 也能够支持
//        $user = Db::name('user')->whereRaw('id=:id',['id'=>19])->select();
//        return json($user);

        //field
        //使用 field() 可以指定要查询的字段
        //使用 field() 可以给指定的字段设置别名
//        Db::name('user')->field('username as name')->select();
//        Db::name('user')->field(['username'=>'name'])->select();
//        return Db::getLastSql();

        //使用 fieldRaw() 方法里 可以直接给字段设置mysql函数
//        $user = Db::name('user')->fieldRaw('id,SUM(price)')->select();

        //使用 field(true)的布尔参数。可以显示的查询所有字段，而不是*

        //使用 withoutFiled() 方法中字段排除，可以屏蔽掉不显示的字段
//        return json(Db::name('user')->withoutField('id')->select());

        //使用field() 方法在新增时，验证字段的合法性
        //Db::name('user')->filed('username,email,details')->insert($data);



        //alias() 方法 给数据库起别名
        Db::name('user')->alias('a')->select();
        return Db::getLastSql();
    }

    //链式查询方法 下
    public function linkDown(){
        //limit()方法  限制获取输出数据的个数
//      $user = Db::name('user')->limit(5)->select();

        //分页模式 传递两个参数 比如从第3条开始显示5条
//        $user = Db::name('user')->limit(2,5)->select();


        //page() 分页方法  优化了limit() 方法 无须计算分页条数
        //第一页
//        Db::name('user')->page(1,5)->select();
        //第二页
//        Db::name('user')->page(2,5)->select();



        //order()
        //使用order() 方法，可以指定排序方式.没有指定第二参数，默认asc
//        $user = Db::name('user')->order('id','desc')->select();
//        //支持数组的方式  对多个字段进行排序
//        Db::name('user')->order(['id'=>'desc','price'=>'asc'])->select();
//        //使用orderRaw() 支持排序的时候指定MYSQL函数
//        Db::name('user')->orderRaw('FIELD(username,"犬夜叉") DESC')->select();


        //group()
        //使用group()，给性别不同的人进行price()字段的总和统计
        //$user = Db::name('user')->fieldRaw('gender,SUM(price)')->group('gender')->select();
       //也可以进行多字段分组统计
       // $user = Db::name('user')->fieldRaw('gender,SUM(price)')->group('gender,password')->select();


        //having() 使用group()分组后，在进行having()筛选
        $result = Db::name('user')->fieldRaw('gender,SUM(price)')->group('gender')->having('SUM(price)>1000')->select();
       return json($result);
        return Db::getLastSql();
   }

   //数据库的高级查询
    public function advanced(){
       //使用 | （OR） &（AND）来实现where条件的高级查询
//       $user = Db::name('user')->where('username|email','like','%xiao%')
//                               ->where('price&uid','>',10)
//                               ->select();

        //使用关联数组  可以在where进行多个字段查询
//        $user = Db::name('user')->where([
//            ['uid','>',10],
//            ['status','>',1],
//            ['price','>',100]
//        ])->select();

        //根据之前的课程中，条件字符串复杂组装，比如使用exp（） 就时运raw()方法
//        $user = Db::name('user')->where([
//            ['status','=',1],
//            ['price','exp',Db::raw('>80')]
//        ])->select();

        //如果有多个where 并且where条件是分离的$map 而 $map 本身有多个条件
        //那么$map条件如果需要先执行结果，再和后续条件判断，也就是加上括号
        //那么需要对这个$map变量，再加上一个中括号处理优先级
//        $map = [
//            ['id','>',0],
//            ['price','exp',Db::raw( '>=80')],
//        ];
//        Db::name('user')->where([$map])->where('status',1)->select();


        //如果 条件中多次出现一个字段，并且需要OR来左右筛选  可以用whereOr
//        Db::name('user')->whereOr([
//          ['username','like','%xiao%'],
//          ['username','like','%xiao111%']
//        ])->select();


        //闭包查询可以连贯，会自动加上括号，更清晰 如果是OR 请用whereOr
//        Db::name('user')->where(function($query){
//            $query->where('uid',"10");
//        })->whereoR(function($query){
//            $query->where('username','like','hjk%');
//        })->select();


        //对于比较复杂或者你不知福如何拼装SQL条件，那么直接使用whereRaw()
        $user = Db::name('user')->whereRaw('(username LIKE "%ghj" AND email LIKE "%123")')->select();
        //whereRaw() 也支持参数绑定操作 具体如下
        $user = Db::name('user')->whereRaw('(username LIKE :username AND email LIKE :email)',
        ['username'=>'%xiao%','email'=>'%163%']
        )->select();
        return Db::getLastSql();


   }

   //比较             getByFieldName()
    public function speedy(){
       //whereColmn() 比较两个知道字段的值
//        Db::name('user')->whereColumn('create_time','>=','update_time')->select();

      //whereFieldName() 查询某个字段的值  FiledName是字段名
//        Db::name('user')->whereEmail('123456@123.com')->find();
//        Db::name('user')->whereUsername('1234')->find();

        //getByFieldName() 方法 查询摸个字段的值，注意只能查询一条 不需要find
//        Db::name('user')->getByEmail('12345@qq.com');

        //getFieldByFieldName() 通过查询得到某个指定字段的单一值
//        Db::name('user')->getFieldByEmail('xiaoxin@163.com','username');

        //when() 通过条件判断  执行闭包里的分支查询
        //true 执行第二个参数
        //false 执行第三个参数
        $user = Db::name('user')->when(false,function($query){
            $query->where('id','>',0);
        },function($query){
            $query->where('username','like','%123');
        })->select();
        return Db::getLastSql();
    }


    //数据库的事务和获取器
    //事务处理
//    1 数据库的表引擎需要是 InnoDB 才可以使用 ，如果不是调整即可
//    2 事务处理，需要执行多个SQL查询，数据是关联恒定的
//    3 如果成功一条查询，改变了数据，而后一条失败，则前面的数据回滚
//    4 如 兜兜给 佳哥 3块钱 ，兜兜 -3 佳哥+3 这时就需要事务处理
     public function mysqlThing(){
       //事务处理
         //自动模式
//         Db::Transaction(function(){
//             Db::name('user')->where('id',19)->save(['price'=>Db::raw('price-3')]);
//
//             Db::name('user1')->where('id',20)->save(['price'=>Db::raw('price+3')]);
//         });

         //手动模式
         Db::startTrans();
         try{
             Db::name('user')->where('id',19)->save(['price'=>Db::raw('price-3')]);
             Db::name('user1')->where('id',20)->save(['price'=>Db::raw('price+3')]);
             Db::commit();
         }catch(\Exception $e){
             echo "执行sql失败，回滚数据";
             Db::rollback();
         }

     }


     //获取器
    public function getter(){
       //1 获取器 的意思就是 ： 将数据的字段进行转换处理再进行操作
        //2  比如在获取数据列表的时候，将获取的到的邮箱字段全部大写操作

        $user = Db::name('user')->withAttr('email',function($value,$data){
            return strtoupper($value);
        })->select();
        return json($user);
    }


    //数据集
    public function collection(){
       //数据集：是查询后的结果集，他是 think\Collection类型 和数组一样
       //很多方法 用到就查
        //获取数据集
        $user = Db::name('user')->select();
        //装换成数组
        dump($user->toArray());
        //将数据集随机打乱
        dump($user->shuffle());
        //删掉数据中的最后一个元素
        dump($user->pop());
        //我使用whereIn
        dump($user->whereIn('id',[19,20,21]));
    }
}


